﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PartyRepository.cs" company="Tuckerman Software">
// Copyright 2012 Tuckerman Software, New Hampshire, USA
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Circles.NHibernateRepository
{
    using System;
    using System.Linq;

    using Circles.Domain;
    using Circles.Persistence;

    using NHibernate;
    using NHibernate.Linq;

    /// <summary>
    /// Concrete implementation of the IPartyRespository using NHibernate.
    /// </summary>
    public class PartyRepository : IPartyRepository
    {
        /// <summary>
        /// The session factory.
        /// </summary>
        private readonly ISession session;

        /// <summary>
        /// Initializes a new instance of the <see cref="PartyRepository"/> class.
        /// </summary>
        /// <param name="session">The current session.</param>
        public PartyRepository(ISession session)
        {
            Guard.NotNull(() => session, session);

            this.session = session;
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="PartyRepository"/> class from being created.
        /// </summary>
        private PartyRepository()
        {
        }

        #region Implementation of IRepository<Party,in Guid>

        /// <summary>
        /// Indexer allowing repository to be accessed like a
        /// collection or array using [] notation.
        /// </summary>
        /// <param name="id">Unique identifier for a party.</param>
        /// <returns>The requested party instance or null.</returns>
        public Party this[Guid id]
        {
            get
            {
                return this.FindById(id);
            }

            set
            {
                if (this.FindById(id) == null)
                {
                    this.Add(value);
                }
                else
                {
                    this.Update(value);
                }
            }
        }

        /// <summary>
        /// Finds all parties.
        /// </summary>
        /// <returns>All party instances or null.</returns>
        public IQueryable<Party> FindAll()
        {
            return this.session.Query<Party>();
        }

        /// <summary>
        /// Finds a party using given identifier.
        /// </summary>
        /// <param name="id">Unique identifier for a party.</param>
        /// <returns>The requested party instance or null.</returns>
        public Party FindById(Guid id)
        {
            return this.session.Get<Party>(id);
        }

        #endregion

        #region Implementation of ISupportSave<in Party,out Guid>

        /// <summary>
        /// Adds the given <see cref="Party"/> instance to the repository.
        /// </summary>
        /// <param name="entity">The party instance to add.</param>
        /// <returns>The assigned unique identifier for this newly added instance.</returns>
        public Guid Add(Party entity)
        {
            Guard.NotNull(() => entity, entity);

            entity.Id = (Guid)(entity.Id == Guid.Empty ? entity.NewId() : entity.Id);

            return (Guid)this.session.Save(entity);
        }

        /// <summary>
        /// Updates the given party instance in the repository.
        /// </summary>
        /// <param name="entity">The party instance to update, 
        /// uniquely identified by its Key value.</param>
        public void Update(Party entity)
        {
            this.session.Update(entity);
        }

        #endregion

        #region Implementation of ISupportDelete<Party,in Guid>

        /// <summary>
        /// Deletes a party instance from the repository.
        /// </summary>
        /// <param name="id">Unique identifier for a person.</param>
        public void Delete(Guid id)
        {
            SessionHelper.Delete<Party>(this.session, id);
        }

        #endregion

        #region Implementation of IPartyRepository

        /// <summary>
        /// Finds all households.
        /// </summary>
        /// <returns>All household instances or null.</returns>
        public IQueryable<Household> FindAllHouseholds()
        {
            return this.session.Query<Household>();
        }

        /// <summary>
        /// Finds all organizations.
        /// </summary>
        /// <returns>All organization instances or null.</returns>
        public IQueryable<Organization> FindAllOrganizations()
        {
            return this.session.Query<Organization>();
        }

        /// <summary>
        /// Finds all persons.
        /// </summary>
        /// <returns>All person instances or null.</returns>
        public IQueryable<Person> FindAllPersons()
        {
            return this.session.Query<Person>();
        }

        /// <summary>
        /// Finds a household using given identifier.
        /// </summary>
        /// <param name="id">Unique identifier for a household.</param>
        /// <returns>The requested household instance or null.</returns>
        public Household FindHouseholdById(Guid id)
        {
            return this.session.Get<Household>(id);
        }

        /// <summary>
        /// Finds an organization using given identifier.
        /// </summary>
        /// <param name="id">Unique identifier for an organization.</param>
        /// <returns>The requested organization instance or null.</returns>
        public Organization FindOrganizationById(Guid id)
        {
            return this.session.Get<Organization>(id);
        }

        /// <summary>
        /// Finds a party type using given identifier.
        /// </summary>
        /// <param name="id">Unique identifier for a party type.</param>
        /// <returns>The requested person instance or null.</returns>
        public PartyType FindPartyTypeById(Guid id)
        {
            return this.session.Get<PartyType>(id);
        }

        /// <summary>
        /// Finds a person using given identifier.
        /// </summary>
        /// <param name="id">Unique identifier for a person.</param>
        /// <returns>The requested person instance or null.</returns>
        public Person FindPersonById(Guid id)
        {
            return this.session.Get<Person>(id);
        }

        #endregion
    }
}
